home *** CD-ROM | disk | FTP | other *** search
- /*
- I call my fixed length numbers "BigFixed" and translate from BigNum's
- to BigFixed's in the PowerAndRemainder routine. These are the assembly
- language routines which are the guts of my program:
-
- (1) PowerMod -- raises a number to a power and reduces it by a modulus. It
- uses a fast binary exponentiation algorithm, reducing by the modulus at
- each step.
- (2) Multiply -- multiplies 2 BigNum's together.
- (3) MultQ -- mutliplies a BigNum by a long int.
- (4) Divide -- divides one BigNum by another and supplies the quotient and
- remainder.
- (5) Compare -- determines the ordering of 2 BigNum's.
-
- Some of the loops have been expanded to make more efficient use of the instruction cache.
- */
-
- #define NumSize 72
-
- typedef struct BigNum
- {
- short numDig;
- unsigned char *dig;
- } BigNum;
-
- typedef struct BigFixed
- {
- unsigned char dig[NumSize*4];
- } BigFixed;
-
- /* We need 72 longs because the division routine needs
- the most significant longword to be zero and
- the speed optimization requires that NumSize be
- a multiple of four. */
-
- void PowerAndRemainder(BigNum *msg, BigNum *exp, BigNum *n,
- BigNum *res);
- void PowerMod(BigFixed *msg, BigFixed *exp, BigFixed *n,
- BigFixed *res);
- void Multiply(BigFixed *src1, BigFixed *src2, BigFixed *dst);
- void MultQ(BigFixed *src1, long src2, BigFixed *dst);
- void Divide(BigFixed *end, BigFixed *sor, BigFixed *dst);
- short Compare(BigFixed *src1, BigFixed *src2);
-
-
- void PowerAndRemainder(BigNum *msg, BigNum *exp, BigNum *n,
- BigNum *res)
- {
- short a, b, numDigits;
- BigFixed msg0, exp0, n0, res0;
-
- for (a = 0; a < NumSize*4; a++)
- {
- b = NumSize*4 - msg->numDig;
- if (a < b) msg0.dig[a] = 0;
- else msg0.dig[a] = msg->dig[a - b];
- b = NumSize*4 - exp->numDig;
- if (a < b) exp0.dig[a] = 0;
- else exp0.dig[a] = exp->dig[a - b];
- b = NumSize*4 - n->numDig;
- if (a < b) n0.dig[a] = 0;
- else n0.dig[a] = n->dig[a - b];
- }
- PowerMod(&msg0, &exp0, &n0, &res0);
- a = 0;
- while (res0.dig[a] == 0) a++;
- numDigits = res->numDig = NumSize*4 - a;
- for (b = 0; b < numDigits; b++)
- res->dig[b] = res0.dig[a++];
- }
-
- void PowerMod(BigFixed *msg, BigFixed *exp, BigFixed *n,
- BigFixed *res)
- {
- BigFixed acc, scrap;
-
- asm
- {
- LEA acc, A0 ; Start with one in
- MOVEQ #NumSize/4-2, D0 ; accumulator
- @Z CLR.L (A0)+
- CLR.L (A0)+
- CLR.L (A0)+
- CLR.L (A0)+
- DBF D0, @Z
- CLR.L (A0)+
- CLR.L (A0)+
- CLR.L (A0)+
- MOVEQ #1, D0
- MOVE.L D0, (A0)
- MOVEA.L exp, A0 ; Put address of
- ; exponent in A0
- CLR.W D2 ; D2 holds position
- ; in exponent
- @6 TST.L 00(A0, D2.W*4) ; Find first longword
- ; of exponent
- BNE @4 ; which is not zero
- CMPI.W #NumSize-1, D2
- BEQ @5 ; If entire exponent
- ; is zero, leave
- ADDQ.W #1, D2
- BRA @6
- @4 CLR.L D1 ; D1 holds the bit #
- @2 PEA acc ; Square accumulator
- PEA acc
- PEA acc
- JSR Multiply
- ADDA.W #12, A7
- MOVE.L n, -(A7) ; Compare accumulator
- PEA acc ; to modulus
- JSR Compare
- ADDQ.W #8, A7
- TST.B D0
- BMI @7 ; If it's less, skip
- ; reduction
- PEA scrap ; Reduce accumulator
- ; modulo "n"
- MOVE.L n, -(A7) ; Quotient not needed,
- PEA acc ; store in "scrap"
- JSR Divide
- ADDA.W #12, A7
- @7 BFTST 00(A0, D2.W*4){D1:1} ; Test a bit in current
- ; longword of exponent
- BEQ @1 ; If zero, skip multiply
- PEA acc ; Multiply accumulator
- PEA acc ; by base
- MOVE.L msg, -(A7)
- JSR Multiply
- ADDA.W #12, A7
- MOVE.L n, -(A7) ; Compare accumulator
- PEA acc ; to modulus
- JSR Compare
- ADDQ.W #8, A7
- TST.B D0
- BMI @1 ; If it's less, skip
- ; reduction
- PEA scrap ; Reduce modulo "n"
- MOVE.L n, -(A7)
- PEA acc
- JSR Divide
- ADDA.W #12, A7
- @1 ADDQ.W #1, D1 ; Increase bit number
- CMPI.B #32, D1
- BLT @2 ; If < 32, loop
- ADDQ.W #1, D2 ; Increase longword #
- CMPI.W #NumSize, D2
- BLT @4 ; If < number size, loop
- @5 LEA acc, A0 ; Copy acc to "res"
- MOVEA.L res, A1
- MOVEQ #NumSize/4-1, D0
- @3 MOVE.L (A0)+, (A1)+
- MOVE.L (A0)+, (A1)+
- MOVE.L (A0)+, (A1)+
- MOVE.L (A0)+, (A1)+
- DBF D0, @3
- }
- }
-
- /* Multiply src1 by src2 and put product in dst */
-
- void Multiply(BigFixed *src1, BigFixed *src2, BigFixed *dst)
- {
- short topStop, botStop;
- BigFixed acc, line;
-
- asm
- {
- MOVEM.L D0-D7/A0-A4, -(A7)
- LEA acc, A0 ; Clear accumulator
- MOVEQ #NumSize/4-1, D0
- @Z CLR.L (A0)+
- CLR.L (A0)+
- CLR.L (A0)+
- CLR.L (A0)+
- DBF D0, @Z
- LEA line, A2 ; "line" holds partial
- ; products
- MOVEA.L src1, A3 ; Move bottom number's
- CLR.W D1 ; address into A3
- @6 TST.L 00(A3, D1.W*4) ; Find first non-zero
- BNE @7 ; longword of bottom #
- ADDQ.W #1, D1
- CMPI.W #NumSize, D1 ; If bottom number 0,
- BEQ @8 ; go to end
- BRA @6 ; Loop
- @7 MOVE.W D1, botStop
- MOVEQ #NumSize - 1, D4 ; D4 holds position in
- ; bottom number
- @4 MOVEA.L src2, A4 ; Move top number's
- CLR.W D1 ; address into A4
- @9 TST.L 00(A4, D1.W*4) ; Find first non-zero
- BNE @A ; longword of top #
- ADDQ.W #1, D1
- CMPI.W #NumSize, D1 ; If top number zero,
- BEQ @8 ; go to end
- BRA @9 ; Loop
- @A SUBQ.W #1, D1
- BPL @X
- CLR.W D1
- @X MOVE.W D1, topStop
- @B CLR.L 00(A2, D1.W*4) ; Clear leading longwords
- DBF D1, @B ; of partial product
- ADDA.W #NumSize * 4, A4 ; Add size
- CLR.L D2 ; D2 is carry register
- MOVE.L 00(A3, D4.W*4), D7 ; Get longword from
- ; bottom number
- MOVEQ #NumSize - 1, D3 ; D3 holds position
- ; in product
- @1 MOVE.L D7, D5 ; Copy longword to D5
- MULU.L -(A4), D6:D5 ; Do 64-bit multiply
- ADD.L D2, D5 ; Add carry to low
- ; longword of product
- CLR.L D2 ; Use D2 as dummy to
- ; extend carry
- ADDX.L D2, D6 ; Add zero to high
- ; longword with carry
- MOVE.L D6, D2 ; Anything in high
- ; longword gets carried
- MOVE.L D5, 00(A2, D3.W*4) ; Store low longword in
- ; partial product
- SUBQ.W #1, D3 ; Loop through all
- CMP.W topStop, D3 ; longwords in top number
- BGE @1
- MOVEA.L A2, A0 ; Now add partial product
- ; to accumulator
- MOVE.L D4, D0 ; Calculate correct
- ; position in product
- LEA acc, A1 ; Get accumulator's addr
- ADDQ.W #1, D0
- ADDA.W #NumSize * 4, A0
- LSL.W #2, D0
- ADDA.W D0, A1
- MOVE.W D4, D1
- MOVE.L -(A1), D0 ; Get longword of product
- SUBQ #1, D1
- ADD.L -(A0), D0 ; Add longword of
- MOVE.L D0, (A1) ; partial product
- TST.W D1 ; If no more longwords,
- BMI @2 ; then branch
- @3 ADDX.L -(A0), -(A1) ; Add next longword
- DBF D1, @3 ; Loop through
- ; entire product
- @2 SUBQ.W #1, D4 ; Loop and do next
- CMP.W botStop, D4 ; longword of bottom #
- BGE @4
- @8 LEA acc, A0 ; Copy product to "dst"
- MOVEA.L dst, A1
- MOVEQ #NumSize/4-1, D0
- @5 MOVE.L (A0)+, (A1)+
- MOVE.L (A0)+, (A1)+
- MOVE.L (A0)+, (A1)+
- MOVE.L (A0)+, (A1)+
- DBF D0, @5
- MOVEM.L (A7)+, D0-D7/A0-A4
- }
- }
-
- /* Multiply src1 by src2 and put product in dst */
-
- void MultQ(BigFixed *src1, long src2, BigFixed *dst)
- {
- BigFixed pro;
-
- asm
- {
- MOVEM.L D0-D7/A0/A1, -(A7)
- LEA pro, A0 ; Clear product
- MOVEQ #NumSize/4-1, D0
- @Z CLR.L (A0)+
- CLR.L (A0)+
- CLR.L (A0)+
- CLR.L (A0)+
- DBF D0, @Z
- LEA pro, A1 ; Get address of
- ; product
- MOVEA.L src1, A0 ; Move top number's
- CLR.W D1 ; address into A0
- @3 TST.L 00(A0, D1.W*4) ; Find first non-zero
- BNE @4 ; longword of top #
- ADDQ.W #1, D1
- CMPI.W #NumSize, D1 ; If top number zero,
- BEQ @5 ; go to end
- BRA @3 ; Loop
- @4 SUBQ.W #1, D1
- BPL @X
- CLR.W D1
- @X MOVEQ #NumSize - 1, D0 ; D0 holds position
- ; in top number
- MOVE.L src2, D7 ; Bottom number
- ; is one longword
- CLR.L D2 ; D2 is carry register
- @1 MOVE.L 00(A0, D0.W*4), D4 ; Get longword of
- ; top number
- MULU.L D7, D5:D4 ; Do 64-bit multiply
- ; by bottom number
- ADD.L D2, D4 ; Add carry
- CLR.L D2 ; Use D2 as dummy to
- ; extend carry
- ADDX.L D2, D5 ; Add zero with carry
- MOVE.L D5, D2 ; High longword
- ; becomes carry
- MOVE.L D4, 00(A1, D0.W*4) ; Put partial product
- ; into result
- SUBQ.W #1, D0 ; Loop through all
- CMP.W D1, D0 ; longwords in top #
- BGE @1
- @5 LEA pro, A0 ; Copy product to "dst"
- MOVEA.L dst, A1
- MOVEQ #NumSize/4-1, D0
- @2 MOVE.L (A0)+, (A1)+
- MOVE.L (A0)+, (A1)+
- MOVE.L (A0)+, (A1)+
- MOVE.L (A0)+, (A1)+
- DBF D0, @2
- MOVEM.L (A7)+, D0-D7/A0/A1
- }
- }
-
- /* Divide end (dividend) by sor (divisor) and put
- quotient in dst. Remainder will end up in end */
-
- void Divide(BigFixed *end, BigFixed *sor, BigFixed *dst)
- {
- long pq;
- BigFixed quo, line;
-
- asm
- {
- MOVEM.L D0-D7/A0-A4, -(A7)
- LEA quo, A0 ; Clear quotient
- MOVEQ #NumSize/4-1, D0
- @Z CLR.L (A0)+
- CLR.L (A0)+
- CLR.L (A0)+
- CLR.L (A0)+
- DBF D0, @Z
- MOVEA.L end, A0 ; Move dividend's
- ; address into A0
- CLR.W D0 ; D0 contains current
- ; position in dividend
- MOVEA.L sor, A1 ; Move divisor's addr
- CLR.W D1 ; into A1
- @2 TST.L 00(A1, D1.W*4) ; This loop finds the
- ; first non-zero
- BNE @G ; longword of the divisor
- ADDQ.W #1, D1 ; & stores the pos in D1
- BRA @2 ; Loop until something
- ; is found
- @G TST.L 00(A0, D0.W*4) ; Find first longword
- BNE @1 ; of dividend
- ADDQ.W #1, D0
- CMPI.W #NumSize, D0 ; If whole dividend zero,
- BEQ @H ; go to end
- BRA @G ; Loop
- @1 LEA quo, A2 ; Address of quotient
- ; is stored in A2
- MOVEQ #NumSize, D2 ; D2 contains current
- ; position in quotient
- SUB.W D1, D2 ; First position will
- SUBQ.W #1, D0 ; be NumSize - D1
- CMP.W D0, D1 ; If dividend smaller
- ; than divisor,
- BLE @H ; then go to end
- ADD.W D0, D2 ; Add to quotient pos
- @C CLR.L pq; ; "pq" holds partial
- ; quotients
- @9 MOVE.L 00(A0, D0.W*4), D3 ; Take a quadword from
- ; dividend to use
- MOVE.L 04(A0, D0.W*4), D4 ; as partial dividend
- MOVE.L 00(A1, D1.W*4), D5 ; Take a longword from
- ; divisor and
- ADDQ.L #1, D5 ; add one
- BNE @E ; If divisor not zero,
- ; go do division
- MOVE.L D3, D4 ; Else, we are dividing
- ; by $10000, so move
- BRA @F ; high longword of
- ; dividend into quotient
- @E DIVU.L D5, D3:D4 ; Do 64-bit division
- @F BEQ @D ; Branch if quotient zero
- ADD.L D4, pq ; Add quotient to
- ; partial quotient
- PEA line ; Multiply quotient
- ; by divisor
- MOVE.L D4, -(A7) ; and store in "line"
- MOVE.L sor, -(A7)
- JSR MultQ
- ADDA.W #12, A7
- LEA line, A3 ; Get quotient-divisor
- ; product
- ADDA.W #NumSize * 4, A3 ; Now subtract
- ; from dividend
- MOVEA.L A0, A4 ; Cpy dividend addr to A4
- MOVE.L D2, D5 ; D2 holds lowest pos
- LSL.W #2, D5 ; of dividend to sub from
- ADDA.W D5, A4 ; Add it to partial
- MOVEQ #NumSize, D7 ; dividend address
- SUB.W D1, D7 ; D7 holds number of
- SUBQ.W #1, D7 ; longwords to subtract
- SMI D5
- MOVE.L (A4), D6 ; Subtract least
- SUB.L -(A3), D6 ; significant longwords
- MOVE.L D6, (A4)
- TST.B D5 ; If there are not any
- ; more longwords
- BNE @B ; to subtract, branch
- @A SUBX.L -(A3), -(A4) ; Subtract rest of
- DBF D7, @A ; longwords with borrow
- @B BRA @9 ; Loop and divide again
- @D MOVE.L pq, D4 ; Get accumulated
- ; partial quotient
- @8 MOVE.L D0, D5 ; Now check to see
- ADDQ.L #1, D5 ; if partial dividend is
- MOVE.L D1, D6 ; less than divisor
- @5 MOVE.L 00(A1, D6.W*4), D7 ; Get longword of divisor
- CMP.L 00(A0, D5.W*4), D7 ; Compare with longword
- ; of dividend, branch
- BCS @3 ; if dividend bigger
- BNE @4 ; If divisor bigger,
- ; then branch
- ADDQ.L #1, D5 ; If these two longwords
- ADDQ.L #1, D6 ; were =, then compare
- CMP.W D2, D5 ; next two longwords and
- BLE @5 ; continue
- @3 MOVEA.L A1, A3 ; Subtract divisor from
- ADDA.W #NumSize * 4, A3 ; partial dividend
- MOVEA.L A0, A4
- MOVE.L D2, D5
- LSL.W #2, D5
- MOVEQ #NumSize, D7
- ADDA.W D5, A4
- SUB.W D1, D7
- SUBQ.W #2, D7
- SMI D5
- MOVE.L (A4), D6
- SUB.L -(A3), D6
- MOVE.L D6, (A4)
- TST.B D5
- BNE @6
- @7 SUBX.L -(A3), -(A4)
- DBF D7, @7
- @6 ADDQ.L #1, D4 ; Add one to quotient
- BRA @8 ; Loop and compare again
- @4 MOVE.L D4, 00(A2, D2.W*4) ; Store partial quotient
- ; in whole quotient
- ADDQ.W #1, D2 ; Increase quotient pos
- ADDQ.W #1, D0 ; Increase dividend pos
- CMPI.W #NumSize, D2
- BLT @C ; Loop until done
- @H LEA quo, A0 ; Copy quotient to "dst"
- MOVEA.L dst, A1 ; Remainder will automat-
- MOVEQ #NumSize/4-1, D0 ; ically end up
- @0 MOVE.L (A0)+, (A1)+ ; in dividend
- MOVE.L (A0)+, (A1)+
- MOVE.L (A0)+, (A1)+
- MOVE.L (A0)+, (A1)+
- DBF D0, @0
- MOVEM.L (A7)+, D0-D7/A0-A4
- }
- }
-
- /* Compare src1 and src2. Returns 1 if src1 > src2,
- 0 if they're equal, and -1 if src1 < src2. */
-
- short Compare(BigFixed *src1, BigFixed *src2)
- {
- asm
- {
- MOVEM.L D1/D2/A0/A1, -(A7)
- MOVEA.L src1, A0 ; Get src1's address
- MOVEA.L src2, A1 ; Get src2's address
- MOVEQ #1, D0 ; Start with +1
- MOVE.L (A0)+, D2
- CMP.L (A1)+, D2 ; Compare 1st longwords
- BLT @1 ; If src1 less, branch
- BNE @2 ; If !=, src1 must
- MOVE.L (A0)+, D2 ; be greater
- CMP.L (A1)+, D2 ; Cmp 3 more longwords
- BCS @1 ; (Unsigned)
- BNE @2
- MOVE.L (A0)+, D2
- CMP.L (A1)+, D2
- BCS @1
- BNE @2
- MOVE.L (A0)+, D2
- CMP.L (A1)+, D2
- BCS @1
- BNE @2
- MOVEQ #NumSize/4-2, D1 ; Number of longwords
- ; remaining / 4
- @3 MOVE.L (A0)+, D2 ; Compare 4 longwords
- CMP.L (A1)+, D2
- BCS @1
- BNE @2
- MOVE.L (A0)+, D2
- CMP.L (A1)+, D2
- BCS @1
- BNE @2
- MOVE.L (A0)+, D2
- CMP.L (A1)+, D2
- BCS @1
- BNE @2
- MOVE.L (A0)+, D2
- CMP.L (A1)+, D2
- BCS @1
- BNE @2
- DBF D1, @3 ; Loop
- CLR.L D0 ; If we get here,
- BRA @2 ; then src1 = src2
- @1 MOVEQ #-1, D0 ; src1 is less
- @2 MOVEM.L (A7)+, D1/D2/A0/A1
- }
- }
-